﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommonExtensions.IListExtensions;
using DBMigrator.Core.DbObjects.Data.What;
using Rhino.Mocks;
using Rhino.Mocks.Constraints;
using Xunit;

namespace DBMigrator.Core.Tests.DbObjects.Data
{
    public class AdditionalWhatTests
    {
        private readonly IAdditionalWhat additionalWhat;
        private readonly IWhatColumnList columnList;
        private readonly AdditionalWhat what;

        public AdditionalWhatTests()
        {
            additionalWhat = MockRepository.GenerateMock<IAdditionalWhat>();
            columnList = MockRepository.GenerateMock<IWhatColumnList>();
            what = new AdditionalWhat(additionalWhat, columnList);
        }

        [Fact]
        public void AndColumnShouldThrowIfColumnNameIsNull()
        {
            Assert.Throws<ArgumentException>(() => what.AndColumn(null));
        }

        [Fact]
        public void AndColumnShouldThrowIfColumnNameIsEmpty()
        {
            Assert.Throws<ArgumentException>(() => what.AndColumn(string.Empty));
        }

        [Fact]
        public void AndColumnShouldAddColumnToColumnList()
        {
            var columnName = StringUtil.Random();
            var expectation = Arg<string[]>.Matches(List.Count(Is.Equal(1)) && List.IsIn(columnName));
            
            columnList.Expect(c => c.AddColumns(expectation));

            what.AndColumn(columnName);

            columnList.VerifyAllExpectations();
        }

        [Fact]
        public void AndColumnShouldReturnAdditionalWhat()
        {
            columnList.Stub(c => c.AddColumns());

            Assert.Equal(additionalWhat, what.AndColumn("ColumnName"));
        }

        [Fact]
        public void AndColumnsShouldThrowIfColumnNamesIsNull()
        {
            Assert.Throws<ArgumentNullException>(() => what.AndColumns(null));
        }

        [Fact]
        public void AndColumnsShouldThrowIfColumnNamesIsEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => what.AndColumns(new string[0]));
        }

        [Fact]
        public void AndColumnsShouldThrowIfAnyColumnNamesAreNull()
        {
            Assert.Throws<ArgumentException>(() => what.AndColumns(StringUtil.Random(), null, StringUtil.Random()));
        }

        [Fact]
        public void AndColumnsShouldThrowIfAnyColumnNamesAreEmpty()
        {
            Assert.Throws<ArgumentException>(() => what.AndColumns(StringUtil.Random(), StringUtil.Random(), 
                string.Empty));
        }

        [Fact]
        public void AndColumnsShouldAddColumnsToColumnList()
        {
            var columnNames = new string[] { StringUtil.Random(), StringUtil.Random() };

            columnList.Expect(c => c.AddColumns(columnNames));

            what.AndColumns(columnNames);

            columnList.VerifyAllExpectations();            
        }

        [Fact]
        public void AndColumnsShouldReturnAdditionalWhat()
        {
            columnList.Stub(c => c.AddColumns());

            Assert.Equal(additionalWhat, what.AndColumns("ColumnName"));
        }

        [Fact]
        public void AndAllColumnsFromShouldThrowIfTableNameIsNull()
        {
            Assert.Throws<ArgumentNullException>(() => what.AndAllColumnsFrom(null));
        }

        [Fact]
        public void AndAllColumnsFromShouldThrowIfTableNameIsEmpty()
        {
            Assert.Throws<ArgumentNullException>(() => what.AndAllColumnsFrom(string.Empty));
        }

        [Fact]
        public void AndAllColumnsFromShouldAddAllColumnsFromTable()
        {
            var tableName = StringUtil.Random();
            columnList.Expect(c => c.AddAllTableColumns(tableName));

            what.AndAllColumnsFrom(tableName);

            columnList.VerifyAllExpectations();
        }

        [Fact]
        public void AndAllColumnsFromShouldReturnAdditionalWhat()
        {
            columnList.Stub(c => c.AddAllTableColumns(Arg<string>.Is.Anything));

            Assert.Equal(additionalWhat, what.AndAllColumnsFrom("TableName"));
        }

        [Fact]
        public void AndColumnsFromShouldThrowIfTableNameIsNull()
        {
            Assert.Throws<ArgumentNullException>(() => what.AndColumnsFrom(null, "ColumnNames"));
        }

        [Fact]
        public void AndColumnsFromShouldThrowIfTableNameIsEmpty()
        {
            Assert.Throws<ArgumentNullException>(() => what.AndColumnsFrom(string.Empty, "ColumnNames"));
        }

        [Fact]
        public void AndColumnsFromShouldThrowIfColumnNamesIsNull()
        {
            Assert.Throws<ArgumentNullException>(() => what.AndColumnsFrom("TableName", null));
        }

        [Fact]
        public void AndColumnsFromShouldThrowIfColumnNamesIsEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => what.AndColumnsFrom("TableName", new string[0]));
        }

        [Fact]
        public void AndColumnsFromShouldThrowIfAnyColumnNamesAreNull()
        {
            Assert.Throws<ArgumentException>(() => what.AndColumnsFrom("TableName", 
                new string[] { null, StringUtil.Random()}));
        }

        [Fact]
        public void AndColumnsFromShouldThrowIfAnyColumnNamesAreEmpty()
        {
            Assert.Throws<ArgumentException>(() => what.AndColumnsFrom("TableName",
                new string[] { StringUtil.Random(), string.Empty }));
        }

        [Fact]
        public void AndColumnsFromShouldAddTableColumns()
        {
            var tableName = StringUtil.Random();
            var columnNames = new string[] { StringUtil.Random() };

            columnList.Expect(c => c.AddTableColumns(tableName, columnNames));

            what.AndColumnsFrom(tableName, columnNames);

            columnList.VerifyAllExpectations();
        }

        [Fact]
        public void AndColumnsFromShouldReturnAdditionalWhat()
        {
            columnList.Stub(c => c.AddTableColumns(Arg<string>.Is.Anything, Arg<string[]>.Is.Anything));

            Assert.Equal(additionalWhat, what.AndColumnsFrom("tableName", "columnName"));
        }
    }
}
